#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017, Niklas Hauser
#
# This file is part of the modm project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# -----------------------------------------------------------------------------

import math

def max_ram_size(target):
    memories = listify(target.get_driver("core")["memory"])
    rams = ((int(m["start"], 16), int(m["start"], 16) + int(m["size"]))
            for m in memories if "rw" in m["access"] and "backup" not in m["name"])
    rams = sorted(rams, key=lambda m: m[0])

    pools = [rams[0]]
    for ram in rams[1:]:
        # is the end address of the last pool the start address of the new pool
        if pools[-1][1] == ram[0]:
            # Set the pool end to the section end
            pools[-1] = (pools[-1][0], ram[1])
        else:
            pools.append(ram)

    return max(p[1] - p[0] for p in pools)

def init(module):
    module.name = ":tlsf"
    module.description = FileReader("README.md")

def prepare(module, options):
    device = options[":target"]
    core = device.get_driver("core")
    if not core or not core["type"].startswith("cortex"):
        return False

    # 4 or 5 are acceptable values (ie. 16 or 32 subdivisions)
    module.add_option(
        EnumerationOption(
            name="subdivisions",
            description="Number of subdivisions per memory pool",
            enumeration=[16, 32],
            default=16))
    # 512kB covers all internal SRAM of any STM32 device
    # 512MB is an architecture limit of ARM Cortex-M
    module.add_option(
        NumericOption(
            name="minimum_pool_size",
            description="Minimum pool size in byte",
            minimum="4Ki",
            maximum="512Mi",
            default="{}Ki".format(int(max_ram_size(options[":target"])/1024))))

    return True

def build(env):
    env.collect(":build:path.include", "modm/ext")
    env.outbasepath = "modm/ext/tlsf"
    env.substitutions = {
        "sl_index_count_log2": math.ceil(math.log2(env["subdivisions"])),
        "fl_index_max": math.ceil(math.log2(env["minimum_pool_size"]))
    }
    env.copy("tlsf.h")
    env.template("tlsf.c.in")
